package com.sky.common.docker;

import com.github.dockerjava.api.command.CreateContainerCmd;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.InspectContainerResponse;
import com.github.dockerjava.api.command.InspectContainerResponse.ContainerState;
import com.github.dockerjava.api.command.PullImageResultCallback;
import com.github.dockerjava.api.model.*;
import com.sky.common.docker.build.ContainerTemplate;
import com.sky.common.docker.build.PortMapping;
import com.sky.common.docker.build.VolumeMapping;
import com.sky.common.docker.container.ContainerInfo;
import com.sky.common.docker.container.ContainerStateInfo;
import com.sky.common.docker.container.ImageInfo;
import com.sky.common.enums.ContainerStatus;
import com.sky.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * docker容器操作实现类
 */
@Component
@Slf4j
public class DockerOperateServiceImpl implements ContainerOperateService {

    @Override
    public String create(ContainerClient client,  ContainerTemplate containerTemplate) {
        //设置镜像名
        CreateContainerCmd cmd = client.getDockerClient().createContainerCmd(containerTemplate.getImageName());
        HostConfig hostConfig = HostConfig.newHostConfig();

        //设置name
        if (containerTemplate.getName() != null) {
            cmd.withName(containerTemplate.getName());
        }

        //设置网络模式
        if (containerTemplate.isHostMode()) {
            hostConfig.withNetworkMode("host");
        }

        //设置重启模式
        if(containerTemplate.isAlwaysRestart()) {
            hostConfig.withRestartPolicy(RestartPolicy.alwaysRestart());
        }else if(containerTemplate.isOnFailureRestart()){
            hostConfig.withRestartPolicy(RestartPolicy.onFailureRestart(3));
        }else if(containerTemplate.isUnlessStopRestart()){
            hostConfig.withRestartPolicy(RestartPolicy.unlessStoppedRestart());
        }

        //设置运行模式
        if(StringUtils.isNotEmpty(containerTemplate.getRuntime())) {
            hostConfig.withRuntime(containerTemplate.getRuntime());
        }

        //处理环境变量
        if (containerTemplate.getEnvMap().size() > 0) {
            List<String> envList = containerTemplate.getEnvMap().entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).collect(Collectors.toList());
            cmd.withEnv(envList);
        }

        //存储卷挂载相关配置
        List<VolumeMapping> volumnBindList = containerTemplate.getVolumeMappingList();
        if (volumnBindList != null && volumnBindList.size() > 0) {
            List<Bind> bindList = new ArrayList<>();
            for (VolumeMapping volumeMapping : volumnBindList) {
                Volume volume = new Volume(volumeMapping.getContainerPath());
                Bind bind = new Bind(volumeMapping.getHostPath(), volume, volumeMapping.isReadOnly() ? AccessMode.ro : AccessMode.rw);
                bindList.add(bind);
            }
            hostConfig.withBinds(bindList);
        }

        //设置端口映射
        List<PortMapping> portMappingList = containerTemplate.getPortMappingList();
        if (portMappingList != null && portMappingList.size() > 0) {
            Ports ports = new Ports();
            for (PortMapping portMapping : portMappingList) {
                ExposedPort exposedPort = portMapping.isUdp() ? ExposedPort.udp(portMapping.getContainerPort()) : ExposedPort.tcp(portMapping.getContainerPort());
                ports.bind(exposedPort, Ports.Binding.bindPort(portMapping.getHostPort()));
            }
            hostConfig.withPortBindings(ports);
        }

        //设置入口点
        if (StringUtils.isNotEmpty(containerTemplate.getEntrypoint())) {
            cmd.withEntrypoint(containerTemplate.getEntrypoint());
        }

        //设置cmd
        if (containerTemplate.getArgList() != null && containerTemplate.getArgList().size() > 0) {
            cmd.withCmd(containerTemplate.getArgList());
        }

        //gpu
        if(containerTemplate.isGpuSupport()) {
            List<String> capability = new ArrayList<>();
            capability.add("gpu");
            List<List<String>> capabilities = new ArrayList<>();
            capabilities.add(capability);
            List<DeviceRequest> deviceRequests = new ArrayList<>();
            DeviceRequest nvidia = new DeviceRequest().withCount(-1).withDriver("nvidia").withCapabilities(capabilities);
            deviceRequests.add(nvidia);
            hostConfig.withDeviceRequests(deviceRequests);
        }


        //内存相关配置
        if(containerTemplate.getShareMemory()>0){
            hostConfig.withShmSize(containerTemplate.getShareMemory());
        }
        if(containerTemplate.getMemory()>0) {
            hostConfig.withMemory(containerTemplate.getMemory());
        }
        if(containerTemplate.getSwapMemory()>0){
            hostConfig.withMemorySwap(containerTemplate.getSwapMemory());
        }
        if(containerTemplate.getKernelMemory()>0){
            hostConfig.withKernelMemory(containerTemplate.getKernelMemory());
        }

        //io相关配置
        if(containerTemplate.getBlockIoWeight()>0){
            hostConfig.withBlkioWeight(containerTemplate.getBlockIoWeight());
        }

        //设置
        cmd.withHostConfig(hostConfig);

        //执行创建容器
        CreateContainerResponse container = cmd.exec();
        return container.getId();
    }

    @Override
    public void start(ContainerClient client, String containerId) {
        client.getDockerClient().startContainerCmd(containerId).exec();
    }

    @Override
    public void stop(ContainerClient client, String containerId) {
        client.getDockerClient().stopContainerCmd(containerId).exec();
    }

    @Override
    public void restart(ContainerClient client, String containerId) {
        client.getDockerClient().restartContainerCmd(containerId).exec();
    }

    @Override
    public void remove(ContainerClient client, String containerId, boolean force) {
        client.getDockerClient().removeContainerCmd(containerId).withForce(force).exec();
    }

    @Override
    public void kill(ContainerClient client, String containerId) {
        client.getDockerClient().killContainerCmd(containerId).exec();
    }

    @Override
    public void pause(ContainerClient client, String containerId) {
        client.getDockerClient().pauseContainerCmd(containerId).exec();
    }

    @Override
    public void unpause(ContainerClient client, String containerId) {
        client.getDockerClient().unpauseContainerCmd(containerId).exec();
    }

    @Override
    public ContainerStateInfo inspect(ContainerClient client, String containerId) {
        InspectContainerResponse response = client.getDockerClient().inspectContainerCmd(containerId).exec();
        ContainerState containerState = response.getState();
        return  ContainerStateInfo.valueOf(containerState);
    }

    @Override
    public List<ContainerInfo> listAll(ContainerClient client) {
        List<Container> containerList = client.getDockerClient().listContainersCmd().withShowAll(true).exec();
        return containerList.stream().map(ContainerInfo::valueOf).collect(Collectors.toList());
    }

    @Override
    public List<ContainerInfo> listByStatus(ContainerClient client, ContainerStatus[] statuses) {
        List<String> statusList = Arrays.stream(statuses).map(ContainerStatus::name).collect(Collectors.toList());
        List<Container> containerList = client.getDockerClient().listContainersCmd().withStatusFilter(statusList).exec();
        return  containerList.stream().map(ContainerInfo::valueOf).collect(Collectors.toList());
    }

    @Override
    public void pullImage(ContainerClient client, String name, String tag) throws InterruptedException {
        PullImageResultCallback callback = new PullImageResultCallback() {
            @Override
            public void onNext(PullResponseItem item) {
                log.info("镜像{}:{} 拉取进度:{}",name,tag,item.getStatus());
                super.onNext(item);
            }
        };
        client.getDockerClient().pullImageCmd(name+":"+tag).exec(callback).awaitCompletion();
        log.info("镜像{}:{} 拉取完成",name,tag);
    }

    @Override
    public List<ImageInfo> listImages(ContainerClient containerClient) {
        List<ImageInfo> imageInfoList = new ArrayList<>();
        List<Image> imageList =  containerClient.getDockerClient().listImagesCmd().exec();
        for (Image image : imageList) {
            for(String repoTag:image.getRepoTags()){
                String[] tagArray = repoTag.split(":");
                ImageInfo imageInfo = new ImageInfo();
                imageInfo.setId(image.getId());
                imageInfo.setSize(image.getSize());
                imageInfo.setCreateTime(new Date(image.getCreated()*1000));
                imageInfo.setName(tagArray[0]);
                imageInfo.setTag(tagArray[1]);
                imageInfoList.add(imageInfo);
            }
        }
        return imageInfoList;
    }
}
